//
//  $Author:: chrisandsusan3587@gmail.com                  $
//    $Date:: 2012-08-04 03:51:58 +0000 (Sat, 04 Aug 2012) $
//     $Rev:: 441                                          $
//

//  CPE 790
//  Chris Davis
//  Final Project

//  project.cu
//  Main function file for GPGPU project

#include "project.h"

int main (int argc, char **argv)
{
	char * message;
    char myFileName[80];
    unsigned long Xsize;
    unsigned long Ysize;
    unsigned long NumWavelengths;
    unsigned long NumCubes;

    int StartingWavelength = 0;
    int WavelengthsToAverage = 1;
    int TotalNumberOfElements;
    int i,j;
	int block = 0;
	int grid = 0;

    unsigned int * singleCube;
    unsigned int * subtractionCube;
    unsigned int * resultsCube;

    double * averagedResults;
    double * averagedGPUResults;
    double returntemp;
    unsigned int temp;

    float elapsedTime;
    float elapsedTimeGPU;
    float elapsedTimeSubtractCPU;
    float elapsedTimeSubtractGPU;
    float tempfloat;

    fpos_t dataPosition;

    cudaEvent_t start, stop;
    cudaEvent_t GPUstart, GPUstop;
    cudaEvent_t CPUstart, CPUstop;
    cudaEvent_t CPUsubtractstart, CPUsubtractstop;
    cudaEvent_t GPUsubtractstart, GPUsubtractstop;


    FILE * FilePointer;
    size_t result;

	message = (char *) malloc (sizeof(char) * 512);

	sprintf(message, "\n=====Starting CPE 790 Project...");
	usermessage(message, 3);

	cudaSetDevice(0);
	cudaFree(0);

	cudaEventCreate(&start);
	cudaEventCreate(&stop);
	cudaEventCreate(&GPUstart);
	cudaEventCreate(&GPUstop);
	cudaEventCreate(&CPUstart);
	cudaEventCreate(&CPUstop);
	cudaEventCreate(&CPUsubtractstart);
	cudaEventCreate(&CPUsubtractstop);
	cudaEventCreate(&GPUsubtractstart);
	cudaEventCreate(&GPUsubtractstop);


	sprintf(myFileName, "%s", argv[1]);
	StartingWavelength = atoi(argv[2]);
	WavelengthsToAverage = atoi(argv[3]);
	block = atoi(argv[4]);
	grid = atoi(argv[5]);

	sprintf(message, "\n=====Starting Wavelength = %d\n=====Number of Wavelengths to Average = %d\n=====Blocks = %d, Grids = %d", StartingWavelength, WavelengthsToAverage, block, grid);
	usermessage(message, 3);

	FilePointer = fopen(myFileName, "r");
	if(FilePointer == NULL)
	{
		fputs("\nFile Opening Error\n",stderr);
		exit(1);
	}

	result = fread(&Xsize, 4, 1, FilePointer);
	if(result != 1)
	{
		fputs("\nFile Reading Error\n", stderr);
		exit(1);
	}

	result = fread(&Ysize, 4, 1, FilePointer);
	result = fread(&NumWavelengths, 4, 1, FilePointer);
	result = fread(&NumCubes, 4, 1, FilePointer);

	sprintf(message, "\n=====Data File Information\n===X:  %d\n===Y:  %d\n===# of Wavelengths:  %d\n===# of Cubes:  %d", Xsize, Ysize, NumWavelengths, NumCubes);
	usermessage(message, 2);

	TotalNumberOfElements = (Xsize * Ysize * NumWavelengths);
	singleCube = (unsigned int *) malloc (sizeof(unsigned int) * TotalNumberOfElements);
	subtractionCube = (unsigned int *) malloc (sizeof(unsigned int) * TotalNumberOfElements);
	resultsCube = (unsigned int *) malloc (sizeof(unsigned int) * TotalNumberOfElements);
	averagedResults = (double *) malloc (sizeof(double) * NumCubes);
	averagedGPUResults = (double *) malloc (sizeof(double) * NumCubes);

	sprintf(message, "=====Number of Elements:  %d", TotalNumberOfElements);
	usermessage(message, 3);

	sprintf(message, "\n=====Size of Information:  %d", sizeof(unsigned int));
	usermessage(message, 3);

	fgetpos (FilePointer,&dataPosition);

	for (j = 0; j < TotalNumberOfElements; j++)
	{
		result = fread(&temp, sizeof(unsigned int), 1, FilePointer);
		singleCube[j] = temp;
	}
	//
	//  Single CPU Subtraction
	//
	for (j = 0; j < TotalNumberOfElements; j++)
	{
		subtractionCube[j] = 1;
	}

	cudaEventRecord(CPUsubtractstart, 0);

	for (i = 0; i < NumCubes; i++)
	{
		resultsCube[i] = singleCube[i] - subtractionCube[i];
	}

	cudaEventRecord(CPUsubtractstop, 0);
	cudaEventSynchronize(CPUsubtractstop);
	cudaEventElapsedTime(&elapsedTimeSubtractCPU, CPUsubtractstart, CPUsubtractstop);

	//
	//  GPU Subtraction
	//
	for (j = 0; j < TotalNumberOfElements; j++)
	{
		subtractionCube[j] = 1;
	}

	cudaEventRecord(GPUsubtractstart, 0);

	for (i = 0; i < NumCubes; i++)
	{
		returntemp = computeGPUSubtraction(singleCube, subtractionCube, resultsCube, Xsize, Ysize, StartingWavelength, WavelengthsToAverage, block, grid);
	}

	cudaEventRecord(GPUsubtractstop, 0);
	cudaEventSynchronize(GPUsubtractstop);
	cudaEventElapsedTime(&elapsedTime, GPUsubtractstart, GPUsubtractstop);
    tempfloat = elapsedTime;

	//
	//  Single CPU Cube Averaging
	//
	cudaEventRecord(start, 0);

	for (i = 0; i < NumCubes; i++)
	{
		//for (j = 0; j < TotalNumberOfElements; j++)
		//{
		//	result = fread(&temp, sizeof(unsigned int), 1, FilePointer);
		//	singleCube[j] = temp;
		//}
   		returntemp = computeAverage(singleCube, Xsize, Ysize, StartingWavelength, WavelengthsToAverage);
		averagedResults[i] = returntemp;
	}

	cudaEventRecord(stop, 0);
	cudaEventSynchronize(stop);
	cudaEventElapsedTime(&elapsedTime, start, stop);


	sprintf(message, "Cube Size, Compute Time (ms), Method, Block Size, Grid Size\n%s,%f,1 CPU,0,0",myFileName,elapsedTime);
	usermessage(message, 1);

	sprintf(message, "%s,%f,1 CPU Subtraction,0,0", myFileName, elapsedTimeSubtractCPU);
	usermessage(message, 1);

	sprintf(message, "%s,%f,GPU Subtraction,0,0", myFileName, tempfloat);
	usermessage(message, 1);

	sprintf(message, "=====First 3 elements of the averaged array:  %f, %f, %f", averagedResults[0], averagedResults[1], averagedResults[2]);
	usermessage(message, 3);

	//
	//  GPU Version
	//
	fsetpos (FilePointer,&dataPosition);
	cudaEventRecord(GPUstart, 0);

	for (i = 0; i < NumCubes; i++)
	{
		//for (j = 0; j < TotalNumberOfElements; j++)
		//{
		//	result = fread(&temp, sizeof(unsigned int), 1, FilePointer);
		//	singleCube[j] = temp;
		//}
		returntemp = computeGPUAverage(singleCube, Xsize, Ysize, StartingWavelength, WavelengthsToAverage, block, grid);
		averagedGPUResults[i] = returntemp;
	}

	cudaEventRecord(GPUstop, 0);
	cudaEventSynchronize(GPUstop);
	cudaEventElapsedTime(&elapsedTimeGPU, GPUstart, GPUstop);

	sprintf(message, "%s,%f,GPU,%d,%d",myFileName,elapsedTimeGPU,block,grid);
	usermessage(message, 1);

	sprintf(message, "=====First 3 elements of the averaged array:  %f, %f, %f", averagedGPUResults[0], averagedGPUResults[1], averagedGPUResults[2]);
	usermessage(message, 3);

	sprintf(message, "\n");
	usermessage(message, 1);

	free(averagedResults);
	free(averagedGPUResults);
    free(singleCube);
    free(subtractionCube);
    free(resultsCube);
	fclose(FilePointer);

	cudaEventDestroy(start);
	cudaEventDestroy(stop);

	cudaEventDestroy(CPUstart);
	cudaEventDestroy(CPUstart);

	cudaEventDestroy(GPUstart);
	cudaEventDestroy(GPUstop);

	cudaEventDestroy(CPUsubtractstart);
	cudaEventDestroy(CPUsubtractstop);

	cudaEventDestroy(GPUsubtractstart);
	cudaEventDestroy(GPUsubtractstop);

	cudaFree(0);

	sprintf(message, "=====Ending CPE 790 Project...\n\n");
	usermessage(message, 3);

	return 1;
}

